#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_INA219.h>
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7789.h> // Hardware-specific library for ST7789
//#include <Fonts/FreeSansBold24pt7b.h>

#define TFT_CS   15
#define TFT_RST  2  
#define TFT_DC   16
#define TFT_BL   12

#ifndef STASSID
#define STASSID "XXX"
#define STAPSK  "123456789"
#endif
const char* OTA_Url = "http://192.168.5.4:7200/ESPOTA/ESP8266_INA219_ST7789_V1.0.1.bin";

Adafruit_INA219 ina219;

Adafruit_ST7789 tft_ST7789 = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);

float capacity_mWh = 0.00000;     //用于累计mWh电量
unsigned long start_time;

// 当升级开始时，打印日志
void update_started()
{
  Serial.println("CALLBACK:  HTTP update process started");
}
// 当升级结束时，打印日志
void update_finished()
{
  Serial.println("CALLBACK:  HTTP update process finished");
}
// 当升级中，打印日志
void update_progress(int cur, int total)
{
  Serial.printf("CALLBACK:  HTTP update process at %d of %d bytes...\n", cur, total);
}
// 当升级失败时，打印日志
void update_error(int err)
{
  Serial.printf("CALLBACK:  HTTP update fatal error code %d\n", err);
}
/**
 * 固件升级函数
 * 在需要升级的地方，加上这个函数即可，例如setup中加的updateBin();
 * 原理：通过http请求获取远程固件，实现升级
 */
void updateBin()
{
  WiFiClient client;
  Serial.println("start update");
  
  // Add optional callback notifiers
  ESPhttpUpdate.onStart(update_started);     // 当升级开始时
  ESPhttpUpdate.onEnd(update_finished);      // 当升级结束时
  ESPhttpUpdate.onProgress(update_progress); // 当升级中
  ESPhttpUpdate.onError(update_error);       // 当升级失败时
 
  Serial.println(OTA_Url);
  Serial.println("start update");
  t_httpUpdate_return ret = ESPhttpUpdate.update(client, OTA_Url);
  Serial.println(ret);
  switch (ret) {
    case HTTP_UPDATE_FAILED:
      Serial.printf("HTTP_UPDATE_FAILD Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
      break;

    case HTTP_UPDATE_NO_UPDATES:
      Serial.println("HTTP_UPDATE_NO_UPDATES");
      break;

    case HTTP_UPDATE_OK:
      Serial.println("HTTP_UPDATE_OK");
      break;
  }
}

void setup(void) {
  delay(10);
  Serial.begin(115200);
  Serial.println("Hello!");
  Serial.println("V1.0.0");
  pinMode(0, INPUT);
  
  // 1. 先配置SPI并禁用MISO，MISO引脚后面用作BL控制引脚
  delay(10);
  SPI.pins(14, -1, 13, -1); // SCK=GPIO14, MOSI=GPIO13, MISO=-1(禁用)
  SPI.begin();
  delay(10);
  
  tft_ST7789.init(240, 240);
  delay(10);
  tft_ST7789.setRotation(2);
  tft_ST7789.setTextSize(2);
  tft_ST7789.fillScreen(ST77XX_WHITE);
  tft_ST7789.setTextColor(ST77XX_BLACK);
  tft_ST7789.setCursor(10, 2);
  tft_ST7789.print("V1.0.0 ST7789 Init OK!");
  delay(10);
  
  pinMode(TFT_BL, OUTPUT);
  digitalWrite(TFT_BL, HIGH); // 开启背光
  // analogWriteRange(100);  // 设置PWM范围0-100
  // analogWrite(TFT_BL, 60);
  
  delay(800);
  if(digitalRead(0) == 0){
    delay(50);
    if(digitalRead(0) == 0){
      WiFi.mode(WIFI_STA);
      WiFi.begin(STASSID, STAPSK);
      unsigned int i = 1;
      while (WiFi.status() != WL_CONNECTED) {
        Serial.print('.');
        tft_ST7789.setCursor(4*i++, 25);
        tft_ST7789.print(".");
        delay(300);
      }
      Serial.print("\r\nConnected! IP address: ");
      Serial.println(WiFi.localIP());
      tft_ST7789.setCursor(3, 50);
      tft_ST7789.print(WiFi.localIP());
      delay(10);
      tft_ST7789.setCursor(3, 80);
      tft_ST7789.print("OTA Start!");
      updateBin();
      tft_ST7789.setCursor(3, 110);
      tft_ST7789.print("OTA End WiFi off!");
      //断网，但是实际上好像没断开
      WiFi.disconnect(true);
      WiFi.mode(WIFI_OFF);
      Serial.print("WiFi.status:");Serial.println(WiFi.status());
    }
  }

  // Initialize the INA219.
  // By default the initialization will use the largest range (32V, 2A).  However
  // you can call a setCalibration function to change this range (see comments).
  if (! ina219.begin()) {
    Serial.println("Failed to find INA219 chip");
    tft_ST7789.setCursor(3, 140);
    tft_ST7789.print("Failed to find INA219 chip");
    while (1) { delay(10); }
  }else{
    Serial.println("Measuring voltage and current with INA219 ...");
    tft_ST7789.setCursor(3, 170);
    tft_ST7789.print("Find INA219 chip");
  }
  ina219.setCalibration_32V_2A();
  // To use a slightly lower 32V, 1A range (higher precision on amps):
  //ina219.setCalibration_32V_1A();
  // Or to use a lower 16V, 400mA range (higher precision on volts and amps):
  //ina219.setCalibration_16V_400mA();

  delay(1500);

  //字号30pixel高度
  //tft_ST7789.fillRoundRect(uint16_t x0, uint16_t y0, uint16_t w, uint16_t h, uint16_t radius, uint16_t color);
  //uint16_t color表示16位颜色分为Red 5bit + Green 6bit + Blue 5bit，分别0-31，0-63，0-31
  //例如RGB(255,255,64)，可以换算为31=0b11111，63=0b111111，64/256*32-1=7=0b00111，uint16_t color = 0b11111 111111 00111=0xFFE7
  //(128,255,64)=0x7FE7，(255,128,192)=0xF9F7，(64,192,255)=0x3AFF
  tft_ST7789.setTextWrap(false);            //取消自动换行
  tft_ST7789.fillScreen(ST77XX_BLACK);
  tft_ST7789.fillRoundRect(4, 4, 232, 55, 6, 0xFFE7);
  tft_ST7789.fillRoundRect(4, 63, 232, 55, 6, 0x7FE7);
  tft_ST7789.fillRoundRect(4, 122, 232, 55, 6, 0xF9F7);
  tft_ST7789.fillRoundRect(4, 181, 232, 55, 6, 0x3AFF);
  tft_ST7789.setTextSize(5);
  //tft_ST7789.setFont(&FreeSansBold24pt7b);
  tft_ST7789.setCursor(207, 16);
  tft_ST7789.print("V");
  tft_ST7789.setCursor(207, 75);
  tft_ST7789.print("A");
  tft_ST7789.setCursor(207, 134);
  tft_ST7789.print("W");
  tft_ST7789.setCursor(180, 193);
  tft_ST7789.print("Wh");

  Serial.println(millis());
  start_time = millis();
}

void loop(void) {
  if((millis() - start_time) >= 500){
    start_time = millis();
    Serial.println(start_time);
    Display_Current();
  }
}

void Display_Current() {
  float shuntvoltage = 0;
  float busvoltage   = 0;
  float current_mA   = 0;
  float current_A    = 0;
  float loadvoltage  = 0;
  float power_mW     = 0;

  shuntvoltage = ina219.getShuntVoltage_mV(); //采样电阻压降
  busvoltage   = ina219.getBusVoltage_V();
  current_mA   = abs(ina219.getCurrent_mA());
  current_A    = current_mA / 1000;
  power_mW     = ina219.getPower_mW();
  loadvoltage  = busvoltage + (shuntvoltage / 1000);
  capacity_mWh = capacity_mWh + power_mW * 0.5 / 3600;    //mW * 500ms转化位mWh
  
  Serial.print("Bus Voltage:   "); Serial.print(busvoltage); Serial.println(" V");
  Serial.print("Shunt Voltage: "); Serial.print(shuntvoltage); Serial.println(" mV");
  Serial.print("Load Voltage:  "); Serial.print(loadvoltage); Serial.println(" V");
  Serial.print("Current_mA:    "); Serial.print(current_mA); Serial.println(" mA");
  Serial.print("Current_A:     "); Serial.print(current_A); Serial.println(" A");
  Serial.print("Power:         "); Serial.print(power_mW); Serial.println(" mW");
  Serial.print("capacity_mWh:  "); Serial.print(capacity_mWh); Serial.println(" mWh");
  Serial.println("");

  //显示电压如12.853 V
  char buffer1[10];
  dtostrf(loadvoltage, 2, 3, buffer1);
  String formatted = String(buffer1);
  while (formatted.length() < 6) {  // 补0到2+1+3位
    formatted = "0" + formatted;
  }
  //tft_ST7789.fillRect(10, 4, 160, 55, 0xFFE7);
  tft_ST7789.setTextColor(ST77XX_BLACK, 0xFFE7);
  tft_ST7789.setCursor(8, 16);
  tft_ST7789.print(formatted);
  Serial.print("str_loadvoltage:");Serial.println(formatted);
  
  //显示电流如2.0011A
  char buffer2[10];
  dtostrf(current_A, 1, 4, buffer2);
  formatted = String(buffer2);
  while (formatted.length() < 6) {  // 补0到6位
    formatted = "0" + formatted;
  }
  //tft_ST7789.fillRect(10, 63, 160, 55, 0x7FE7);
  tft_ST7789.setTextColor(ST77XX_BLACK, 0x7FE7);
  tft_ST7789.setCursor(8, 75);
  tft_ST7789.print(formatted);
  Serial.print("str_current_A:");Serial.println(formatted);
  
  //功率<1000.0mW显示为mW，小数点前3位后1位，例如900.3mW
  //功率≥1000.0mW并＜10000.0mW显示为W，小数点前1位后3位，例如1.005W
  //功率大于等于10000.0mW显示为W，小数点前2位后2位，例如48.05W
  char buffer3[10];
  if (power_mW < 1000) {
    dtostrf(power_mW, 3, 1, buffer3);
    formatted = String(buffer3);
    while (formatted.length() < 5) {  // 补0到5位
      formatted = "0" + formatted;
    }
    //tft_ST7789.fillRect(10, 122, 130, 55, 0xF9F7);
    tft_ST7789.setTextColor(ST77XX_BLACK, 0xF9F7);
    tft_ST7789.setCursor(8, 134);
    tft_ST7789.print(formatted);
    tft_ST7789.setTextSize(4);
    tft_ST7789.setCursor(183, 141);
    tft_ST7789.print("m");
    tft_ST7789.setTextSize(5);
    Serial.print("str_power_mW");Serial.println(formatted);
  } else if (power_mW < 10000) {
    float power_W = power_mW / 1000;
    dtostrf(power_W, 1, 3, buffer3);
    formatted = String(buffer3);
    while (formatted.length() < 5) {  // 补0到5位
      formatted = "0" + formatted;
    }
    //tft_ST7789.fillRect(10, 122, 130, 55, 0xF9F7);
    tft_ST7789.setTextColor(ST77XX_BLACK, 0xF9F7);
    tft_ST7789.setCursor(8, 134);
    tft_ST7789.print(formatted);
    tft_ST7789.setTextSize(4);
    tft_ST7789.setCursor(183, 141);
    tft_ST7789.print(" ");  //把m清掉
    tft_ST7789.setTextSize(5);
    Serial.print("str_power_mW");Serial.println(formatted);
  } else {
    float power_W = power_mW / 1000;
    dtostrf(power_W, 2, 2, buffer3);
    formatted = String(buffer3);
    while (formatted.length() < 5) {  // 补0到5位
      formatted = "0" + formatted;
    }
    //tft_ST7789.fillRect(10, 122, 130, 55, 0xF9F7);
    tft_ST7789.setTextColor(ST77XX_BLACK, 0xF9F7);
    tft_ST7789.setCursor(8, 134);
    tft_ST7789.print(formatted);
    tft_ST7789.setTextSize(4);
    tft_ST7789.setCursor(183, 141);
    tft_ST7789.print(" ");  //把m清掉
    tft_ST7789.setTextSize(5);
    Serial.print("str_power_mW");Serial.println(formatted);
  }
  
  
  //电量取0.001~9.999mWh和00.01WH~48.00Wh
  char buffer4[10];
  if (capacity_mWh < 10) {
    dtostrf(capacity_mWh, 1, 3, buffer4);
    formatted = String(buffer4);
    while (formatted.length() < 5) {  // 补0到5位
      formatted = "0" + formatted;
    }
    //tft_ST7789.fillRect(10, 181, 110, 55, 0x3AFF);
    tft_ST7789.setTextColor(ST77XX_BLACK, 0x3AFF);
    tft_ST7789.setCursor(8, 193);
    tft_ST7789.print(formatted);
    tft_ST7789.setTextSize(4);
    tft_ST7789.setCursor(156, 200);
    tft_ST7789.print("m");
    tft_ST7789.setTextSize(5);
    Serial.print("str_capacity");Serial.println(formatted);
  } else {
    float capacity_Wh = capacity_mWh / 1000;
    unsigned int mwh = int(capacity_mWh) % 10;
    dtostrf(capacity_Wh, 2, 2, buffer4);
    formatted = String(buffer4);
    while (formatted.length() < 5) {  // 补0到5位
      formatted = "0" + formatted;
    }
    //tft_ST7789.fillRect(10, 181, 110, 55, 0x3AFF);
    tft_ST7789.setTextColor(ST77XX_BLACK, 0x3AFF);
    tft_ST7789.setCursor(8, 193);
    tft_ST7789.print(formatted);
    tft_ST7789.setTextSize(4);
    tft_ST7789.setCursor(156, 200);
    tft_ST7789.print(String(mwh));  //把m清掉用小号的字体替代
    tft_ST7789.setTextSize(5);
    Serial.print("str_capacity");Serial.println(formatted);
  }
}
